/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package DAO.Financial;

import DAO.exceptions.IllegalOrphanException;
import DAO.exceptions.NonexistentEntityException;
import DAO.exceptions.PreexistingEntityException;
import FinancialEntity.Company;
import FinancialEntity.Quote;
import FinancialEntity.Stock;
import FinancialEntity.StockPK;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityNotFoundException;
import javax.persistence.Query;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;

/**
 *
 * @author Sebastian
 */
public class StockDAO implements Serializable, DAOFinancial {
    
    public void create(Stock stock, EntityManager em) throws PreexistingEntityException, Exception {
        if (stock.getStockPK() == null) {
            stock.setStockPK(new StockPK());
        }
        if (stock.getQuoteList() == null) {
            stock.setQuoteList(new ArrayList<Quote>());
        }
        stock.getStockPK().setCompanyid(stock.getCompany().getId());
        try {
            Company company = stock.getCompany();
            if (company != null) {
                company = em.getReference(company.getClass(), company.getId());
                stock.setCompany(company);
            }
            List<Quote> attachedQuoteList = new ArrayList<Quote>();
            for (Quote quoteListQuoteToAttach : stock.getQuoteList()) {
                quoteListQuoteToAttach = em.getReference(quoteListQuoteToAttach.getClass(), quoteListQuoteToAttach.getQuotePK());
                attachedQuoteList.add(quoteListQuoteToAttach);
            }
            stock.setQuoteList(attachedQuoteList);
            em.persist(stock);
            if (company != null) {
                company.getStockList().add(stock);
                company = em.merge(company);
            }
            for (Quote quoteListQuote : stock.getQuoteList()) {
                Stock oldStockOfQuoteListQuote = quoteListQuote.getStock();
                quoteListQuote.setStock(stock);
                quoteListQuote = em.merge(quoteListQuote);
                if (oldStockOfQuoteListQuote != null) {
                    oldStockOfQuoteListQuote.getQuoteList().remove(quoteListQuote);
                    oldStockOfQuoteListQuote = em.merge(oldStockOfQuoteListQuote);
                }
            }
            em.getTransaction().commit();
        } catch (Exception ex) {
            if (findStock(stock.getStockPK(), em) != null) {
                throw new PreexistingEntityException("Stock " + stock + " already exists.", ex);
            }
            throw ex;
        } 
    }

    public void edit(Stock stock, EntityManager em) throws IllegalOrphanException, NonexistentEntityException, Exception {
        stock.getStockPK().setCompanyid(stock.getCompany().getId());
        try {
            Stock persistentStock = em.find(Stock.class, stock.getStockPK());
            Company companyOld = persistentStock.getCompany();
            Company companyNew = stock.getCompany();
            List<Quote> quoteListOld = persistentStock.getQuoteList();
            List<Quote> quoteListNew = stock.getQuoteList();
            List<String> illegalOrphanMessages = null;
            for (Quote quoteListOldQuote : quoteListOld) {
                if (!quoteListNew.contains(quoteListOldQuote)) {
                    if (illegalOrphanMessages == null) {
                        illegalOrphanMessages = new ArrayList<String>();
                    }
                    illegalOrphanMessages.add("You must retain Quote " + quoteListOldQuote + " since its stock field is not nullable.");
                }
            }
            if (illegalOrphanMessages != null) {
                throw new IllegalOrphanException(illegalOrphanMessages);
            }
            if (companyNew != null) {
                companyNew = em.getReference(companyNew.getClass(), companyNew.getId());
                stock.setCompany(companyNew);
            }
            List<Quote> attachedQuoteListNew = new ArrayList<Quote>();
            for (Quote quoteListNewQuoteToAttach : quoteListNew) {
                quoteListNewQuoteToAttach = em.getReference(quoteListNewQuoteToAttach.getClass(), quoteListNewQuoteToAttach.getQuotePK());
                attachedQuoteListNew.add(quoteListNewQuoteToAttach);
            }
            quoteListNew = attachedQuoteListNew;
            stock.setQuoteList(quoteListNew);
            stock = em.merge(stock);
            if (companyOld != null && !companyOld.equals(companyNew)) {
                companyOld.getStockList().remove(stock);
                companyOld = em.merge(companyOld);
            }
            if (companyNew != null && !companyNew.equals(companyOld)) {
                companyNew.getStockList().add(stock);
                companyNew = em.merge(companyNew);
            }
            for (Quote quoteListNewQuote : quoteListNew) {
                if (!quoteListOld.contains(quoteListNewQuote)) {
                    Stock oldStockOfQuoteListNewQuote = quoteListNewQuote.getStock();
                    quoteListNewQuote.setStock(stock);
                    quoteListNewQuote = em.merge(quoteListNewQuote);
                    if (oldStockOfQuoteListNewQuote != null && !oldStockOfQuoteListNewQuote.equals(stock)) {
                        oldStockOfQuoteListNewQuote.getQuoteList().remove(quoteListNewQuote);
                        oldStockOfQuoteListNewQuote = em.merge(oldStockOfQuoteListNewQuote);
                    }
                }
            }
        } catch (Exception ex) {
            String msg = ex.getLocalizedMessage();
            if (msg == null || msg.length() == 0) {
                StockPK id = stock.getStockPK();
                if (findStock(id, em) == null) {
                    throw new NonexistentEntityException("The stock with id " + id + " no longer exists.");
                }
            }
            throw ex;
        } 
    }

    public void destroy(StockPK id, EntityManager em) throws IllegalOrphanException, NonexistentEntityException {
            Stock stock;
            try {
                stock = em.getReference(Stock.class, id);
                stock.getStockPK();
            } catch (EntityNotFoundException enfe) {
                throw new NonexistentEntityException("The stock with id " + id + " no longer exists.", enfe);
            }
            List<String> illegalOrphanMessages = null;
            List<Quote> quoteListOrphanCheck = stock.getQuoteList();
            for (Quote quoteListOrphanCheckQuote : quoteListOrphanCheck) {
                if (illegalOrphanMessages == null) {
                    illegalOrphanMessages = new ArrayList<String>();
                }
                illegalOrphanMessages.add("This Stock (" + stock + ") cannot be destroyed since the Quote " + quoteListOrphanCheckQuote + " in its quoteList field has a non-nullable stock field.");
            }
            if (illegalOrphanMessages != null) {
                throw new IllegalOrphanException(illegalOrphanMessages);
            }
            Company company = stock.getCompany();
            if (company != null) {
                company.getStockList().remove(stock);
                company = em.merge(company);
            }
            em.remove(stock);
    }

    public List<Stock> findStockEntities(EntityManager em) {
        return findStockEntities(true, -1, -1, em);
    }

    public List<Stock> findStockEntities(int maxResults, int firstResult, EntityManager em) {
        return findStockEntities(false, maxResults, firstResult, em);
    }

    private List<Stock> findStockEntities(boolean all, int maxResults, int firstResult, EntityManager em) {
            CriteriaQuery cq = em.getCriteriaBuilder().createQuery();
            cq.select(cq.from(Stock.class));
            Query q = em.createQuery(cq);
            if (!all) {
                q.setMaxResults(maxResults);
                q.setFirstResult(firstResult);
            }
            return q.getResultList();
    }

    public Stock findStock(StockPK id, EntityManager em) {
        return em.find(Stock.class, id);
    }

    public int getStockCount(EntityManager em) {
            CriteriaQuery cq = em.getCriteriaBuilder().createQuery();
            Root<Stock> rt = cq.from(Stock.class);
            cq.select(em.getCriteriaBuilder().count(rt));
            Query q = em.createQuery(cq);
            return ((Long) q.getSingleResult()).intValue();
        
    }
    
}
